#include "ei2c.h"
#include "util.h"

#include "systick.h"

uint8_t ack;
uint8_t slaveAddr;
#define EI2C_SPEED_LOW 140
#define EI2C_SPEED_STANDARD 2
#define EI2C_SPEED_HIGH 2
volatile uint8_t ei2c_speed = EI2C_SPEED_STANDARD;

/**
 * @brief set emulating i2c 
 * 
 * @param io_sda sda pin
 * @param io_scl scl pin
 * @param addr slave address
 * @param speed 10, 100, 400(kHz)
 * @return int 
 */
void ei2c_init(void)
{
	rcu_periph_clock_enable(I2C0_SCL_GPIO_CLK);
	gpio_mode_set(I2C0_SCL_GPIO_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, I2C0_SCL_PIN);
	gpio_output_options_set(I2C0_SCL_GPIO_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, I2C0_SCL_PIN);
	GPIO_BOP(I2C0_SCL_GPIO_PORT) = I2C0_SCL_PIN;

	rcu_periph_clock_enable(I2C0_SDA_GPIO_CLK);
	gpio_mode_set(I2C0_SDA_GPIO_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, I2C0_SDA_PIN);
	gpio_output_options_set(I2C0_SDA_GPIO_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, I2C0_SDA_PIN);
	GPIO_BOP(I2C0_SDA_GPIO_PORT) = I2C0_SDA_PIN;
}

inline void ei2c_sda(uint8_t state)
{
	if (state) {
		GPIO_BOP(I2C0_SDA_GPIO_PORT) = I2C0_SDA_PIN;
	} else {
		GPIO_BC(I2C0_SDA_GPIO_PORT) = I2C0_SDA_PIN;
	}
}

inline void ei2c_scl(uint8_t state)
{
	if (state) {
		GPIO_BOP(I2C0_SCL_GPIO_PORT) = I2C0_SCL_PIN;
	} else {
		GPIO_BC(I2C0_SCL_GPIO_PORT) = I2C0_SCL_PIN;
	}
}

void ei2c_sdaOut(void)
{
	gpio_mode_set(I2C0_SDA_GPIO_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, I2C0_SDA_PIN);
	gpio_output_options_set(I2C0_SDA_GPIO_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, I2C0_SDA_PIN);
	GPIO_BOP(I2C0_SDA_GPIO_PORT) = I2C0_SDA_PIN;
}

void ei2c_sdaIn(void)
{
	rcu_periph_clock_enable(RCU_CFGCMP);
	gpio_mode_set(I2C0_SDA_GPIO_PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, I2C0_SDA_PIN);
}

inline uint8_t ei2c_getSda(void)
{
	if (gpio_input_bit_get(I2C0_SDA_GPIO_PORT, I2C0_SDA_PIN) == SET) {
		return 1;
	} else {
		return 0;
	}
}

///////////////////////////////////////////////////////////////////

void ei2c_delayUs(uint32_t uscount)
{
	volatile uint32_t temp = uscount * 2;

	for (int i = 0; i < 8; i++) {
		uscount = temp * 2;
		temp = uscount * 2;
	}
}

inline void ei2c_start(void)
{
	ei2c_sda(1);
	ei2c_scl(1);
	ei2c_delayUs(4);

	ei2c_sda(0);
	ei2c_delayUs(4);

	ei2c_scl(0);
}

inline void ei2c_stop(void)
{
	ei2c_sda(0);
	ei2c_delayUs(2);

	ei2c_scl(1);
	ei2c_delayUs(10);

	ei2c_sda(1);
	ei2c_delayUs(10);
}

inline void ei2c_sendByte(uint8_t c)
{
	uint8_t bit_Cnt;

	for (bit_Cnt = 0; bit_Cnt < 8; bit_Cnt++) {
		if ((c << bit_Cnt) & 0x80) {
			ei2c_sda(1);
		} else {
			ei2c_sda(0);
		}
		ei2c_delayUs(3);
		ei2c_scl(1);
		ei2c_delayUs(4);
		ei2c_scl(0);
	}

	ei2c_delayUs(1);
	ei2c_sda(1);
	ei2c_delayUs(3);
	ei2c_scl(1);
	ei2c_delayUs(3);

	if (ei2c_getSda() != 0) {
		ack = 0;
	} else {
		ack = 1;
	}
	ei2c_scl(0);
	ei2c_delayUs(3);
}

inline uint8_t ei2c_rcvByte(void)
{
	uint8_t retc;
	uint8_t bit_Cnt;

	retc = 0;
	ei2c_sda(1);
	for (bit_Cnt = 0; bit_Cnt < 8; bit_Cnt++) {
		ei2c_delayUs(1);
		ei2c_scl(0);
		ei2c_delayUs(4);
		ei2c_scl(1);
		ei2c_delayUs(2);
		retc = retc << 1;
		if (ei2c_getSda() != 0) {
			retc = retc + 1;
		}
		ei2c_delayUs(2);
	}
	ei2c_scl(0);
	ei2c_delayUs(5);
	return retc;
}

inline void ei2c_ack(uint8_t a)
{
	if (a == 0) {
		ei2c_sda(0);
	} else {
		ei2c_sda(1);
	}

	ei2c_delayUs(8);
	ei2c_scl(1);
	ei2c_delayUs(15);
	ei2c_scl(0);
	ei2c_delayUs(8);
}

////////////////////////////////////////////////////////////////////
uint8_t ei2c_memWrite(uint8_t sla, uint8_t suba, uint8_t *s, uint8_t no)
{
	uint8_t i;

	ei2c_start();

	ei2c_sendByte(sla);

	if (ack == 0) {
		ei2c_stop();
		return FALSE;
	}
	ei2c_sendByte(suba);
	if (ack == 0) {
		ei2c_stop();
		return FALSE;
	}

	for (i = 0; i < no; i++) {
		ei2c_sendByte(*s);
		if (ack == 0) {
			ei2c_stop();
			return FALSE;
		}
		s++;
	}
	ei2c_stop();
	return TRUE;
}

uint8_t ei2c_memRead(uint8_t sla, uint8_t suba, uint8_t *s, uint8_t no)
{
	uint8_t i;
	ei2c_start();
	ei2c_sendByte(sla);
	if (ack == 0) {
		ei2c_stop();
		*s = 0x00;
		return FALSE;
	}
	ei2c_sendByte(suba);
	if (ack == 0) {
		ei2c_stop();
		*s = 0x00;
		return FALSE;
	}
	ei2c_start();
	ei2c_sendByte(sla + 1);
	if (ack == 0) {
		ei2c_stop();
		*s = 0x00;
		return FALSE;
	}
	for (i = 0; i < no - 1; i++) {
		*s = ei2c_rcvByte();
		ei2c_ack(0);
		s++;
	}
	*s = ei2c_rcvByte();
	ei2c_ack(1);
	ei2c_stop();
	return TRUE;
}

uint8_t ei2c_read1Byte(uint8_t RegAddr)
{
	uint8_t p_data = 0;

	if (ei2c_memRead(slaveAddr, RegAddr, &p_data, 1) != FALSE) {
		return p_data;
	}
	return 0;
}

uint8_t ei2c_write1Byte(uint8_t RegAddr, uint8_t d)
{
	uint8_t flag;

	flag = ei2c_memWrite(slaveAddr, RegAddr, &d, 1);

	return flag;
}

uint8_t ei2c_writeNByte(uint8_t RegAddr, uint8_t *d, uint8_t N)
{
	uint8_t flag;

	flag = ei2c_memWrite(slaveAddr, RegAddr, d, N);

	return flag;
}
